/**
 * @file fw_interface.c
 * @brief
 * @author henry.cai (henry.cai@queclink.com)
 * @version 1.0
 * @date 2024-09-04
 *
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-04 <td>1.0     <td>henry.cai     <td>内容
 * </table>
 */
#include <stdio.h>
#include <stdint.h>
#include "misc_api.h"

#include "task_misc.h"
#include "misc_log.h"
#include "hwmisc.h"
#include "misc_event.h"

#include "FreeRTOS.h"
#include "timers.h"
#include "global.h"
#include "task_misc.h"
#include "misc_api.h"

/**
 * @brief 获取BOOT版本
 * @param  p_fw_version 软件版本结构体
 * @return int32_t
 */
int32_t tbox_get_boot_version(struct FW_VER_STRU *p_fw_version)
{
    return 0;
}

/**
 * @brief 获取固件版本
 * @param  p_fw_version My Param doc
 * @return int32_t
 */
int32_t tbox_get_fw_version(struct FW_VER_STRU *p_fw_version)
{
    return 0;
}

/**
 * @brief 获取硬件版本号
 * @param  p_hw_version 硬件版本号存放结构体变量
 * @return int32_t 0 表示获取成功; others 表示获取失败
 */
int32_t tbox_get_hw_version(struct HW_VER_STRU *p_hw_version)
{
    if (p_hw_version)
    {
        snprintf(p_hw_version->ver, sizeof(p_hw_version->ver),
                 "%s", get_hw_ver());
    }

    return 0;
}

/**
 * @brief 获取编译日期
 * @param  p_date 编译日期
 * @return int32_t
 */
int32_t tbox_get_fw_builddate(char *p_date)
{
    return 0;
}

/**
 * @brief 获取固件校验码
 * @param  p_date 编译日期
 * @return uint32_t 校验码
 */
uint32_t tbox_get_fw_checksum(void)
{
    return 0;
}

/********************************** STSTEM EVENT ***************************************** */
#include "bsp.h"
/**
 * @brief 定时器回调
 * @param  pxTimer  定时器句柄
 */
void syscall_timeout_callback(TimerHandle_t pxTimer)
{
    int32_t id = 0;

    if (NULL == pxTimer)
    {
        log_e("syscall_timeout_callback pxTimer handle is none!\r\n");
        return;
    }

    id = (int32_t)pvTimerGetTimerID(pxTimer);
    switch (id)
    {
        case 0x5A:
        {
            misc_event_set(SYS_EVT_REBOOT);
        }
        break;

        case 0xA5:
        {
            misc_event_set(SYS_EVT_POWEROFF);
        }
        break;
    }
}

/**
 * @brief 整机重启,实际仅发送事件,并启动5s超时计时器,如果计时器到达仍未能重启，则强制重启设备
 * @return int32_t
 */

TimerHandle_t  reboot_timer;
char system_reboot_off_flag = 0;

char get_system_reboot_off_flag(void)
{
    return system_reboot_off_flag;
}

int32_t tbox_system_reboot(uint32_t delay_reboot_ms)
{
    static TimerHandle_t myTimer = NULL;


    if(0 == delay_reboot_ms) {
        misc_event_set(SYS_EVT_REBOOT);
        system_reboot_off_flag |= SYS_EVT_REBOOT;
		return SUCC;
    }

    if (NULL == (myTimer = xTimerCreate("reboot_timer",             // Just a text name, not used by the kernel.
                                        delay_reboot_ms,                       // The timer period in ticks.
                                        pdFALSE,                     // The timers will auto-reload themselves when they expire.
                                        (void *)0x5A,               // Assign each timer a unique id equal to its array index.
                                        syscall_timeout_callback))) // Each timer calls the same callback when it expires.
    {
        log_e("create a reboot timer failed!\r\n");
        Error_Handler();

        return -EIO;
    }

    reboot_timer = myTimer;

    if( pdPASS != xTimerStart(myTimer, delay_reboot_ms)) {
        log_e("Start a reboot timer failed!\r\n");
        return -EIO;
    }

    system_reboot_off_flag |= SYS_EVT_REBOOT;

    return SUCC;
}

/**
 * @brief 整机关机/低功耗，实际仅发送事件,并启动超时计时器,如果计时器到达仍未能关机，则强制关闭设备
 * @return int32_t
 */
int32_t tbox_system_poweroff(uint32_t delay_power_ms)
{
    static TimerHandle_t myTimer = NULL;

    // 1. 立即关机
    if(0 == delay_power_ms) {
        misc_event_set(SYS_EVT_POWEROFF);
        system_reboot_off_flag |= SYS_EVT_POWEROFF;
		return SUCC;
    }

    // 2. 延迟关机
    if (NULL == (myTimer = xTimerCreate("poweroff_timer",           // Just a text name, not used by the kernel.
                                        delay_power_ms,                       // The timer period in ticks.
                                        pdFALSE,                     // The timers will auto-reload themselves when they expire.
                                        (void *)0xA5,               // Assign each timer a unique id equal to its array index.
                                        syscall_timeout_callback))) // Each timer calls the same callback when it expires.
    {
        log_e("create a poweroff timer failed!\r\n");
        Error_Handler();

        return -EIO;
    }

    if( pdPASS != xTimerStart(myTimer, delay_power_ms)) {
		log_e("Start a poweroff timer failed!\r\n");
    }

    system_reboot_off_flag |= SYS_EVT_POWEROFF;
	
    return SUCC;
}

#include "misc/misc_server.h"
/**
 * @brief 设备恢复出厂设置
 * @return int32_t 
 */
int32_t tbox_system_restore(uint32_t delay_reboot_ms)
{
    misc_server_ssl_restore();
    
    // 参考poweroff/poweron增加事件处理
    tbox_system_reboot(delay_reboot_ms);

    return SUCC;
}

/********************************** PARAM READ & WRITE ***************************************** */
#include "flash/key_params/key_params.h"
#include "flash/protocol_params/protocol_params.h"

extern int32_t load_quec_sn(char *sn, ssize_t len);
extern int8_t load_apn_key_params(apn_param_t *apn, ssize_t apn_len);
/// @brief 获取设备参数sn
/// @param sn 
/// @return 
int32_t tbox_get_sn(char *sn, uint32_t max_size)
{
    int32_t len = 0;

    if(!strlen(dev_prm.sn))
    {
        log_e("sn no ready, try get sn from the config!");
        if (config_get(CONFIG_ID_SN, dev_prm.sn) < 0) {
            log_e("load sn failed, please use AT+WSN to set sn!\r\n");
            return -EIO;
        }
    }

    if(0 < (len = snprintf(sn, max_size, "%s", dev_prm.sn)))
    {
        return len; // SUCC
    }

    return 0;
}


/// @brief 设置设备参数sn
/// @param sn 
/// @return 
int32_t tbox_set_sn(char *sn)
{
    if(sn && strlen(sn) > 0)
    {
        config_update_with_callback(CONFIG_ID_SN, sn, NULL);
        return SUCC;
    }

    return -EIO;
}

/**
 * @brief 清空SN
 * @return int32_t 
 */
int32_t tbox_clr_sn(void) 
{
    char sn[SN_MAX_SIZE] = {0};
    config_set(CONFIG_ID_SN, sn);
    return SUCC;
}

char *lvl_str[ELOG_LVL_VERBOSE + 1] = {
    "ASSERT",
    "ERROR",
    "WARN",
    "INFO",
    "DEBUG",
    "VERBOSE"
};
/// @brief 设置打印调试等级
/// @param enable 
/// @param level 
/// @return 
int32_t tbox_set_logctrl(uint8_t enable, uint8_t lvl, char *tag)
{
    log_params_t log = {0};

    log.enable = enable;
    if(lvl <= ELOG_LVL_VERBOSE)
        log.level  = lvl;

    if(tag)
        snprintf(log.filter_tag, sizeof(log.filter_tag), "%s", tag);
    else 
        memset(log.filter_tag, 0, sizeof(log.filter_tag));
    
    /** 保存LOG配置参数 */
    if(config_set(CONFIG_ID_LOG, &log))
    {
        log_i("save logger config:%s, level:%s, fliter_tag:%s\r\n", 
                            log.enable ? "enable":"disable", 
                            lvl_str[log.level],
                            log.filter_tag);
    }

    if(log.enable)
    {
        elog_set_output_enabled(true);
        if(log.level <= ELOG_LVL_VERBOSE)
            elog_set_filter_lvl(log.level);
        
        elog_set_filter_tag(log.filter_tag);
    }
    else
    {
        elog_set_output_enabled(false);
    }

    

    return 0;
}


/// @brief 设置打印调试等级
/// @param enable 
/// @param level 
/// @return 
int32_t tbox_get_logctrl(uint8_t *enable, uint8_t *lvl, char *tag)
{
    log_params_t log = {0};

    if(!config_get(CONFIG_ID_LOG, &log))
    {
        log_e("load logger config failed, set to default(disable & error level)!\r\n");
        log.enable = true;
        log.level = ELOG_LVL_DEBUG;
        memset(log.filter_tag, 0, sizeof(log.filter_tag));
    }
    
    if(tag)
    {
        sprintf(tag, "%s", log.filter_tag);
    }

    if(lvl)
    {
        *lvl = log.level;
    }

    if(enable)
    {
        *enable = log.enable;
    }

    return 0;
}


/**
 * @brief 判断是被是否处于DQA模式
 * @return true  处于DQA模式
 * @return false 不是处于DQA模式
 */
bool tbox_dqa_mode_get(void)
{
    return dev_sta.dqa_mode;
}

/**
 * @brief 设备进入DQA模式
 */
void tbox_dqa_mode_set(uint8_t status)
{
    dev_sta.dqa_mode = status ? true : false;
}